#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "IRBuilder.hpp"
#include "Module.hpp"
#include "Type.hpp"

#include <iostream>
#include <memory>

// 定义一个从常数值获取/创建 ConstantInt 类实例化的宏，方便多次调用
#define CONST_INT(num) \
    ConstantInt::get(num, module)

// 定义一个从常数值获取/创建 ConstantFP 类实例化的宏，方便多次调用
#define CONST_FP(num) \
    ConstantFP::get(num, module)

int main() {
    auto module = new Module();
    auto builder = new IRBuilder(nullptr, module);
    Type *Int32Type = module->get_int32_type();

    // 全局变量 b
    auto initializer = ConstantZero::get(Int32Type, module);
    auto b = GlobalVariable::create("b", module, Int32Type, false, initializer);

    // main 函数
    auto mainFun = Function::create(FunctionType::get(Int32Type, {}), "main", module);
    auto bb = BasicBlock::create(module, "entry", mainFun);
    builder->set_insert_point(bb);

    // 为函数返回值分配空间
    auto retAlloca = builder->create_alloca(Int32Type);
    // main 函数默认 ret 0
    builder->create_store(CONST_INT(0), retAlloca);

    // b = 1
    builder->create_store(CONST_INT(1), b);

    // 创建数组 a
    auto *arrayType = ArrayType::get(Int32Type, 20);
    auto aAlloca = builder->create_alloca(arrayType);

    // a[0] = 28
    auto a0GEP = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(0)});
    builder->create_store(CONST_INT(28), a0GEP);

    // a[1] = a[0] / 2
    auto a0Load = builder->create_load(a0GEP);
    auto div = builder->create_isdiv(a0Load, CONST_INT(2));
    auto a1GEP = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(1)});
    builder->create_store(div, a1GEP);

    // a[2] = a[1] * 10
    auto a1Load = builder->create_load(a1GEP);
    auto mul = builder->create_imul(a1Load, CONST_INT(10));
    auto a2GEP = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(2)});
    builder->create_store(mul, a2GEP);

    // a[3] = a[2] - b
    auto a2Load = builder->create_load(a2GEP);
    auto bLoad = builder->create_load(b);
    auto sub = builder->create_isub(a2Load, bLoad);
    auto a3GEP = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(3)});
    builder->create_store(sub, a3GEP);

    // return a[3]
    auto a3Load = builder->create_load(a3GEP);
    builder->create_ret(a3Load);

    // 输出 module 中的所有 IR 指令
    std::cout << module->print();
    delete module;
    delete builder;
    return 0;
}
